from typing import Optional
from unicodedata import lookup

from django.utils.translation import gettext as _
from django.utils import timezone as dj_timezone

from core import errors
from apps.app_users.models import UserProfile
from apps.app_tx_meeting.models import MeetingUser


class MeetingUserWrapper:
    def __init__(self, user: UserProfile):
        self.user = user
        # MeetingUser instance
        self._meeting_user = None

    @property
    def meeting_user(self) -> MeetingUser:
        if self._meeting_user is None:
            self._meeting_user = self.get_meeting_user(user=self.user)

        return self._meeting_user

    @meeting_user.setter
    def meeting_user(self, val: MeetingUser):
        self._meeting_user = val

    def refresh(self) -> MeetingUser:
        self._meeting_user = None
        return self.meeting_user

    def get_or_create_meeting_user(self) -> MeetingUser:
        return self.get_meeting_user(self.user, create_not_exists=True)

    @staticmethod
    def get_meeting_user(user: UserProfile, create_not_exists: bool = False) -> MeetingUser:
        """
        不存在时创建一个普通用户权限的实例返回，由create_not_exists指定是否保存到数据库
        """
        urole = MeetingUser.objects.select_related('user').filter(user_id=user.id).first()
        if urole:
            return urole

        nt = dj_timezone.now()
        urole = MeetingUser(
            user=user,
            role=MeetingUser.Role.REGULAR.value,
            status=MeetingUser.UserStatus.ACTIVE.value,
            creation_time=nt, update_time=nt
        )
        if create_not_exists:
            urole.save(force_insert=True)

        return urole

    def is_admin(self) -> bool:
        """是否是管理员"""
        role = self.meeting_user
        return role.is_admin()

    def is_active_user(self) -> bool:
        """是否是有效用户"""
        role = self.meeting_user
        return role.is_active()

    def set_admin(self, val: bool = True, update_db: bool = True):
        obj = self.meeting_user
        if val:
            role = MeetingUser.Role.ADMIN.value
        else:
            role = MeetingUser.Role.REGULAR.value

        obj.role = role

        if update_db:
            # id无效时，用户角色对象是没有保存到数据库的
            if not obj.id:
                obj.save()
                return

            MeetingUserManager.set_user_role(meeting_user=obj, role=role)

    def set_status(self, val: bool = True, update_db: bool = True):
        obj = self.meeting_user
        if val:
            status = MeetingUser.UserStatus.ACTIVE.value
        else:
            status = MeetingUser.UserStatus.INACTIVE.value

        obj.status = status

        if update_db:
            # id无效时，用户角色对象是没有保存到数据库的
            if not obj.id:
                obj.save()
                return

            MeetingUserManager.set_user_status(meeting_user=obj, status=status)


class MeetingUserManager:
    @staticmethod
    def get_meeting_user_by_id(meeting_user_id: str) -> Optional[MeetingUser]:
        return MeetingUser.objects.select_related('user').filter(id=meeting_user_id).first()

    @staticmethod
    def set_user_role(meeting_user: MeetingUser, role: str) -> MeetingUser:
        """
        设置会议预定用户的角色

        :raises: InvalidArgument
        """
        if role not in MeetingUser.Role.values:
            raise errors.InvalidArgument(message=_('用户角色无效'))

        meeting_user.role = role
        meeting_user.save(update_fields=['role', 'update_time'])
        return meeting_user

    @staticmethod
    def set_user_role_by_id(meeting_user_id: str, role: str) -> MeetingUser:
        """
        设置会议预定用户的角色

        :raises: TargetNotExist，InvalidArgument
        """
        meeting_user = MeetingUserManager.get_meeting_user_by_id(meeting_user_id=meeting_user_id)
        if meeting_user is None:
            raise errors.TargetNotExist(message=_('用户不存在'))

        return MeetingUserManager.set_user_role(meeting_user=meeting_user, role=role)

    @staticmethod
    def set_user_status(meeting_user: MeetingUser, status: str) -> MeetingUser:
        """
        设置会议预定用户的状态

        :raises: InvalidArgument
        """
        if status not in MeetingUser.UserStatus.values:
            raise errors.InvalidArgument(message=_('用户状态无效'))

        meeting_user.status = status
        meeting_user.save(update_fields=['status', 'update_time'])
        return meeting_user

    @staticmethod
    def set_user_status_by_id(meeting_user_id: str, status: str) -> MeetingUser:
        """
        设置会议预定用户的状态

        :raises: TargetNotExist，InvalidArgument
        """
        meeting_user = MeetingUserManager.get_meeting_user_by_id(meeting_user_id=meeting_user_id)
        if meeting_user is None:
            raise errors.TargetNotExist(message=_('用户不存在'))

        return MeetingUserManager.set_user_status(meeting_user=meeting_user, status=status)

    @staticmethod
    def filter_meeting_user_qs(status: str = None, role: str = None, search: str = None):
        lookups = {}
        if status:
            lookups['status'] = status

        if role:
            lookups['role'] = role

        if search:
            lookups['user__username__icontains'] = search

        queryset = MeetingUser.objects.select_related('user').all()
        if lookups:
            queryset = queryset.filter(**lookups)

        return queryset.order_by('-creation_time')
